
class _md5_utility
{
...
private:
static const char* const get_hex() noexcept
{
static constexpr
const char str16[17] = "0123456789abcdef";
return str16;
}

public:
static
void change_hex(uint32_t a, char h[9]) noexcept
{
	h[8] = 0;
	char* p = &h[0];  // revised by Yijun WANG
	for ( int32_t i = 0; i < 4; i ++ ) {
		//little endian
		uint8_t b = (uint8_t)a;
		*p ++ = get_hex()[b >> 4];
		*p ++ = get_hex()[b & 0x0F];
		a >>= 8;
	}
}
};

// Md5Helper

template <class TString>
inline
void Md5Helper::GenerateSalt(TString& str)
{
	assert( sizeof(typename StringTraits<TString>::CharType) == sizeof(char) );

	StringTraits<TString>::Clear(str);
	AdvRandomNumber2 randNum;
	randNum.Init();
	for ( int32_t i = 0; i < 16; ++ i ) {
		switch ( randNum.Next() % 3 ) {
		case 1:
			StringTraits<TString>::Append('A', str);  //may throw
			StringTraits<TString>::Append('A' + (randNum.Next() % 26), str);  //may throw
			break;
		case 2:
			StringTraits<TString>::Append('a', str);  //may throw
			StringTraits<TString>::Append('a' + (randNum.Next() % 26), str);  //may throw
			break;
		default:
			StringTraits<TString>::Append('0', str);  //may throw
			StringTraits<TString>::Append('0' + (randNum.Next() % 10), str);  //may throw
			break;
		}
	}
}

template <class TString>
inline
void Md5Helper::CalcHash(const typename StringTraits<TString>::CharType* szSrc, const typename StringTraits<TString>::CharType* szSalt, TString& str)
{
	assert( sizeof(typename StringTraits<TString>::CharType) == sizeof(char) );

	Md5Calc mc;
	mc.Initialize();
	if ( !mc.Input((const uint8_t*)szSrc, CharTraits<typename StringTraits<TString>::CharType>::CalcLength(szSrc)) )
		ExceptionTraits::ThrowOverflow();  //throw
	if ( !mc.Input((const uint8_t*)szSalt, CharTraits<typename StringTraits<TString>::CharType>::CalcLength(szSalt)) )
		ExceptionTraits::ThrowOverflow();  //throw
	if ( !mc.End() )
		ExceptionTraits::ThrowOverflow();  //throw
	StringTraits<TString>::Clear(str);
	const Md5_Value& v = mc.GetValue();
	char h[9];
	_md5_utility::change_hex(v.a, h);
	StringTraits<TString>::Append(h, str);  //may throw
	_md5_utility::change_hex(v.b, h);
	StringTraits<TString>::Append(h, str);  //may throw
	_md5_utility::change_hex(v.c, h);
	StringTraits<TString>::Append(h, str);  //may throw
	_md5_utility::change_hex(v.d, h);
	StringTraits<TString>::Append(h, str);  //may throw
	//other ways
	StringTraits<TString>::Append(szSalt, str);  //may throw
}
